import { ObjectDirective, nextTick, watch } from 'vue';
import Viewer from 'viewerjs';
// 防抖
import { debounce } from 'throttle-debounce';

let name = 'viewer', debug = false;
export const viewerDirective: ObjectDirective<any, Function> = {
  created(el, binding, vnode) {
    const debouncedCreateViewer = debounce(50, createViewer)
    debouncedCreateViewer(el, binding.value)

    // 创建watch监听options表达式变化
    createWatcher(el, binding, vnode, debouncedCreateViewer)

    // 是否监听dom变化
    if (!binding.modifiers.static) {
      // 增加dom变化监听
      createObserver(el, binding.value, debouncedCreateViewer, binding.modifiers.rebuild)
    }
  },
  unmounted(el) {
    // 销毁dom变化监听
    destroyObserver(el)
    // 销毁指令表达式监听
    destroyWatcher(el)
    // 销毁viewer
    destroyViewer(el)
  }
}
const install = (app: any, { name = 'viewer', debug = false }) => {
  app.directive(name, viewerDirective)
};

/**
 * 创建和销毁Viewer
 * @param el 
 * @param {Object} options => binding.value
 * @param rebuild 
 */
function createViewer(el: any, options: any, rebuild = false) {
  // nextTick执行，否则可能漏掉未渲染完的子元素
  nextTick(() => {
    if (rebuild || !el[`__${name}`]) {
      destroyViewer(el)
      el[`__${name}`] = new Viewer(el, options)
    } else {
      el[`__${name}`].update()
    }
  })
}
function destroyViewer(el: any) {
  if (!el[`__${name}`]) {
    return
  }
  el[`__${name}`].destroy()
  delete el[`__${name}`]
}

/**
 * 监听Dom变化
 * @param el 
 * @param options 
 * @param debouncedCreateViewer 
 * @param rebuild 
 */
function createObserver(el: any, options: any, debouncedCreateViewer: any, rebuild: any) {
  destroyObserver(el)
  // @ts-ignore
  const MutationObserver = global.MutationObserver || global.WebKitMutationObserver || global.MozMutationObserver
  if (!MutationObserver) {
    console.log('observer not supported')
    return
  }
  const observer = new MutationObserver(function (mutations:any) {
    mutations.forEach(function (mutation:any) {
      console.log('viewer mutation:' + mutation.type)
      debouncedCreateViewer(el, options, rebuild)
    })
  })
  const config = { attributes: true, childList: true, characterData: true, subtree: true };
  observer.observe(el, config);
  el['__viewerMutationObserver'] = observer;
}
function destroyObserver(el: any) {
  if (!el['__viewerMutationObserver']) {
    return
  }
  el['__viewerMutationObserver'].disconnect()
  delete el['__viewerMutationObserver']
}

/**
 * 监听options表达式变化
 * @param el 
 * @param param1 
 * @param vnode 
 * @param debouncedCreateViewer 
 */
function createWatcher(el: any, binding: any, vnode: any, debouncedCreateViewer: any) {
  const { expression } = binding;
  const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/;
  if (!expression || !simplePathRE.test(expression)) {
    console.log('only simple dot-delimited paths can create watcher')
    return
  }
  el['__viewerUnwatch'] = watch(expression, function (newVal, oldVal) {
    console.log('change detected by watcher: ', expression)
    debouncedCreateViewer(el, newVal, true)
  }, {
    deep: true
  })
}
function destroyWatcher(el: any) {
  if (!el['__viewerUnwatch']) {
    return
  }
  el['__viewerUnwatch']()
  delete el['__viewerUnwatch']
}


export default {
  install
}
